mem hotplug: Fix an incorrect sanity check in memory add
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 4 Feb 2010 13:09:30 +0000 (13:09 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 4 Feb 2010 13:09:30 +0000 (13:09 +0000)
Current, memory hot-add will fail if the new added memory is bigger
than current max_pages. This is really a stupid checking, considering
user may hot-add the biggest address riser card firstly.

This patch fix this issue. It check if all new added memory is
unpopulated, if yes, then it is ok.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
xen/arch/x86/x86_64/mm.c

index 03b61cc34f7aa471b9b65a818bf6280395c3e69e..caccc0b1e5e8998851cea62826ca71051dc4986c 100644 (file)
@@ -1332,9 +1332,12 @@ int transfer_pages_to_heap(struct mem_hotadd_info *info)
 
 int mem_hotadd_check(unsigned long spfn, unsigned long epfn)
 {
-    unsigned long s, e, length;
+    unsigned long s, e, length, sidx, eidx;
 
-    if ( (spfn >= epfn) || (spfn < max_page) )
+    if ( (spfn >= epfn) )
+        return 0;
+
+    if (pfn_to_pdx(epfn) > (FRAMETABLE_SIZE / sizeof(*frame_table)))
         return 0;
 
     if ( (spfn | epfn) & ((1UL << PAGETABLE_ORDER) - 1) )
@@ -1343,6 +1346,20 @@ int mem_hotadd_check(unsigned long spfn, unsigned long epfn)
     if ( (spfn | epfn) & pfn_hole_mask )
         return 0;
 
+    /* Make sure the new range is not present now */
+    sidx = ((pfn_to_pdx(spfn) + PDX_GROUP_COUNT - 1)  & ~(PDX_GROUP_COUNT - 1))
+            / PDX_GROUP_COUNT;
+    eidx = (pfn_to_pdx(epfn - 1) & ~(PDX_GROUP_COUNT - 1)) / PDX_GROUP_COUNT;
+    if (sidx >= eidx)
+        return 0;
+
+    s = find_next_zero_bit(pdx_group_valid, eidx, sidx);
+    if ( s > eidx )
+        return 0;
+    e = find_next_bit(pdx_group_valid, eidx, s);
+    if ( e < eidx )
+        return 0;
+
     /* Caculate at most required m2p/compat m2p/frametable pages */
     s = (spfn & ~((1UL << (L2_PAGETABLE_SHIFT - 3)) - 1));
     e = (epfn + (1UL << (L2_PAGETABLE_SHIFT - 3)) - 1) &
@@ -1433,8 +1450,11 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
         goto destroy_frametable;
 
     /* Set max_page as setup_m2p_table will use it*/
-    max_page = epfn;
-    max_pdx = pfn_to_pdx(max_page - 1) + 1;
+    if (max_page < epfn)
+    {
+        max_page = epfn;
+        max_pdx = pfn_to_pdx(max_page - 1) + 1;
+    }
     total_pages += epfn - spfn;
 
     set_pdx_range(spfn, epfn);
@@ -1443,7 +1463,7 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
     if ( ret )
         goto destroy_m2p;
 
-    for ( i = old_max; i < epfn; i++ )
+    for ( i = spfn; i < epfn; i++ )
         if ( iommu_map_page(dom0, i, i) )
             break;